//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#ifndef _FTL_H_
#define _FTL_H_

#include <flashctrl.h>

#define DBGOUT(Cls,Lvl,s) if (Lvl>=5) s;
#define DBGPRN(x) printf(#x"= %x\n", x)

typedef IDeviceDriver *PDRIVER;

#define printf kprintf

EXTERN_C int PageNeeded(int size);

INLINE UInt32 Truncate(UInt32 val, UInt32 align)
{
    return val &~ (align - 1);
}

INLINE UInt32 RoundUp(UInt32 val, UInt32 align)
{
    return Truncate(val + align - 1, align);
}

#define   SECSZ       512
#define MAX_FLASH_PARTS 1

// mtd_info  type field
#define MTD_NORFLASH		3
#define MTD_OTHER		14
#define MTD_UNKNOWN		15

//mtd_info flags
#define MTD_CLEAR_BITS		1       // Bits can be cleared (flash)
#define MTD_SET_BITS		2       // Bits can be set
#define MTD_ERASEABLE		4       // Has an erase function
#define MTD_WRITEB_WRITEABLE	8       // Direct IO is possible
#define MTD_XIP			32	// eXecute-In-Place possible

// Some common devices / combinations of capabilities
#define MTD_CAP_NORFLASH        (MTD_CLEAR_BITS|MTD_ERASEABLE)
#define MTD_WRITEABLE		(MTD_CLEAR_BITS|MTD_SET_BITS)

// erase_info state
#define MTD_ERASE_PENDING      	0x01
#define MTD_ERASING		        0x02
#define MTD_ERASE_SUSPEND	    0x04
#define MTD_ERASE_DONE          0x08
#define MTD_ERASE_FAILED        0x10

// control code for ftl level
typedef enum FTLControl {
    FTLControl_DeleteBlock               = 0x10000001
} FTLControl;

struct erase_info {
    UInt32 addr;		  //Address (in bytes) of the block to be erased
    UInt32 len;		 //Length of the erase to perform. This must always be equal to mtd->erasesize.
                     //I.e. you may only erase one erase block in a single erase request.

    //These are used internally by the driver module.
    UInt32 time;
    UInt32 retries;
    UInt32 dev;
    UInt32 cell;

    /*
     * This is a pointer to a function provided by the user module which will be called when the erase request
     * is completed.The callback function may be called from IRQ context or from a timer,
     * and must not block or schedule.
     */
    void (*callback) (struct erase_info *self);

    UInt32 priv;		  //Private data for use by the user module which schedules the erase.
    UInt8 state;		  //The current state of the erase request.
    struct erase_info *next;//The driver module may use this field for queuing requests.
};

#define ERASE_UNIT 0x20000 // 128k erase unit for intel

#define FLASHBASE  VM_FLUSH
#define FTLPARTLAB "intel28F320B3"

//#define BLOCK_SIZE_BITS 10
//#define BLOCK_SIZE (1<<BLOCK_SIZE_BITS)
//#define MAXIO 128*512

#define HDIO_GETGEO		0x0301	/* get device geometry */
#define BLKRRPART  0x0302	/* re-read partition table */
#define BLKGETSIZE 0x0303	/* return device size */
#define BLKFLSBUF  0x0304	/* flush buffer cache */

typedef struct erase_unit_header_t {
    UInt8	LinkTargetTuple[5];
    UInt8	DataOrgTuple[10];
    UInt8	NumTransferUnits;
    UInt32	EraseCount;
    UInt16	LogicalEUN;
    UInt8	BlockSize;
    UInt8	EraseUnitSize;
    UInt16	FirstPhysicalEUN;
    UInt16	NumEraseUnits;
    UInt32	FormattedSize;
    UInt32	FirstVMAddress;
    UInt16	NumVMPages;
    UInt8	Flags;
    UInt8	Code;
    UInt32	SerialNumber;
    UInt32	AltEUHOffset;
    UInt32	BAMOffset;
    UInt8	Reserved[12];
    UInt8	EndTuple[2];
} erase_unit_header_t;

/* Flags in erase_unit_header_t */
#define HIDDEN_AREA		0x01
#define REVERSE_POLARITY	0x02
#define DOUBLE_BAI		0x04

/* Definitions for block allocation information */

#define BLOCK_FREE(b)		((b) == 0xffffffff)
#define BLOCK_DELETED(b)	(((b) == 0) || ((b) == 0xfffffffe))

#define BLOCK_TYPE(b)		((b) & 0x7f)
#define BLOCK_ADDRESS(b)	((b) & ~0x7f)
#define BLOCK_NUMBER(b)		((b) >> 9)
#define BLOCK_CONTROL		0x30
#define BLOCK_DATA		0x40
#define BLOCK_REPLACEMENT	0x60
#define BLOCK_BAD		0x70

    struct eun_info_t {
        UInt32			Offset;
        UInt32			EraseCount;
        UInt32			Free;
        UInt32			Deleted;
    };

    struct xfer_info_t {
        UInt32			Offset;
        UInt32			EraseCount;
        UInt16			state;
    };

// Each memory region corresponds to a minor device
typedef struct partition_t {
    UInt32 size;	 // Total size of the MTD
    UInt32 erasesize;
    PDRIVER mtd;
//    CONDITION IntrPoint; /* unused */
//    MUTEX Lock;
    IMutex *Lock;

    UInt32		state;
    UInt32		*VirtualBlockMap;
    UInt32		FreeTotal;

    struct eun_info_t *EUNInfo;

    struct xfer_info_t *XferInfo;
    UInt16		bam_index;
    UInt32		*bam_cache;
    UInt16		DataUnits;
    UInt32		BlocksPerUnit;
    erase_unit_header_t	header;
    int 		open;
} partition_t;

// Partition state flags
#define FTL_FORMATTED	0x01

// Transfer unit states
#define XFER_UNKNOWN	0x00
#define XFER_ERASING	0x01
#define XFER_ERASED	0x02
#define XFER_PREPARED	0x03
#define XFER_FAILED	0x04

EXTERN_C int ftl_delete(partition_t *part, UInt32 sector, UInt32 nblocks);
EXTERN_C int ftl_read(partition_t *part, Byte * buffer,
		    UInt32 sector, UInt32 nblocks);
EXTERN_C int ftl_write(partition_t *part, Byte * buffer,
		     UInt32 sector, UInt32 nblocks);
EXTERN_C int ftl_init(partition_t *part,PDRIVER mtd);
EXTERN_C int ftl_close(partition_t *part);
EXTERN_C void ftl_freepart(partition_t *part);

//used for debug ftl
void print_header(erase_unit_header_t *hdr);
void print_part(partition_t *part);
void TestFtl();
//EXTERN_C void __cdecl Chat();

//used for format tool
EXTERN_C int ftl_write_fmt(partition_t *part, Byte * buffer,
		     UInt32 sector, UInt32 nblocks);
EXTERN_C int ftl_init_fmt(partition_t *part,PDRIVER mtd);

//used for defrag
EXTERN_C int reclaim_block_all(partition_t *part);

//used for addin.cpp
int find_xfer(partition_t *part);
int copy_erase_unit(partition_t *part, UInt16 srcnum,
			   UInt16 xfernum);
int erase_xfer(partition_t *part, UInt16 xfernum);
int scan_header(partition_t *part);
int build_maps(partition_t *part);
int reclaim_block(partition_t *part);
UInt32 find_free(partition_t *part);
int set_bam_entry(partition_t *part, UInt32 log_addr,
			 UInt32 virt_addr);

int ReadFlash(
        PDRIVER pDevice,
        UInt64 offset,
        Byte *pBuffer,
        UInt32 uSize,
        UInt32 *pRetSize);
int WriteFlash(
        PDRIVER pDevice,
        UInt64 offset,
        Byte *pBuffer,
        UInt32 uSize,
        UInt32 *pRetSize);
int EraseFlash(
        PDRIVER pDevice,
        UInt32 offset);
int GetFlashInfo(
        PDRIVER pDevice,
        UInt32 *pSize,
        UInt32 *pErasesize);



#endif /* _FTL_H_ */
